package corewarsxxi.logic;

import java.io.Serializable;

/**
 * MemoryField contains an AddressingMode and a stored value.
 *
 * @version 1.0
 * @see     corewarsxxi.logic.AddressingMode
 * @author  Luís Fonseca, ei10139 @ FEUP
 */
public class MemoryField implements Cloneable, Serializable
{
    /**
     *
     */
    protected AddressingMode aMode;
    /**
     *
     */
    protected int value;
    /**
     *
     */
    protected boolean aField;

    /**
     *
     * @param aMode
     * @param value
     * @param aField
     */
    public MemoryField(AddressingMode aMode, int value, boolean aField)
    {
        this.aMode = aMode;
        Core c = Core.getInstance();
        if(c != null && value != 0)
        {
            value %= c.getSize();
            if(value < 0)
                value = c.getSize() + value;
        }

        this.value = value;
        this.aField = aField;
    }

    /**
     *
     * @param aMode
     * @param value
     */
    public MemoryField(AddressingMode aMode, int value)
    {
        this(aMode, value, true);
    }

    /**
     *
     * @param aMode
     */
    public MemoryField(AddressingMode aMode)
    {
        this(aMode, 0);
    }

    /**
     *
     */
    public MemoryField()
    {
        this(AMDirect.self);
    }

    /**
     *
     * @return
     */
    public int getValue()
    {
        return aMode.getValue(value, aField);
    }

    /**
     *
     * @return
     */
    protected int postIncValue()
    {
        if(++value > Core.getInstance().getSize())
            setValue(1);
        
        return value - 1;
    }

    /**
     *
     * @return
     */
    protected int preDecValue()
    {
        if(value-- > 0)
            return value;

        return this.value = Core.getInstance().getSize() - 1;
    }

    /**
     *
     * @param aMode
     * @param aField
     */
    public void changeAddressingMode(AddressingMode aMode, boolean aField)
    {
        this.aMode = aMode;
        this.aField = aField;
    }

    /**
     *
     * @param aMode
     */
    public void changeAddressingMode(AddressingMode aMode) {
        this.changeAddressingMode(aMode, true);
    }

    /**
     *
     * @return
     */
    public AddressingMode getAddressingMode()
    {
        return this.aMode;
    }

    @Override
    public Object clone()
    {
        return new MemoryField(aMode, value, aField);
    }

    /**
     *
     * @return
     */
    protected int getStoredValue() {
        return this.value;
    }

    /**
     *
     * @param value
     */
    protected void setStoredValue(int value)
    {
        value %= Core.getInstance().getSize();
        if(value < 0)
            value = Core.getInstance().getSize() + value;

        this.setValue(value);
    }

    @Override
    public String toString()
    {
        return this.aMode.toString(this.aField) + this.value;
    }

    /**
     * @param value the value to set
     */
    public void setValue(int value) {
        this.value = value;
    }
}
